webSocket Protocol

21-12-03 ์—…๋ฐ์ดํŠธ

๐Ÿ“ก ์‘๋‹ต์„ ํ•ด์ฃผ๋Š” ์„œ๋ฒ„

์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์š”์ฒญ์— ๋งž๋Š” ์‘๋‹ต์„ ํ•ด์ฃผ๋Š” ๊ฒƒ. ์„œ๋ฒ„์™€ ๊ด€๋ จ๋œ ๊ฒƒ์„ ์กฐ๊ธˆ์”ฉ ์•Œ์•„๊ฐ€๋ฉด์„œ ํ˜ธ๊ธฐ์‹ฌ์ด ์ƒ๊ฒผ์—ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ์‘๋‹ต์„ ๋ฐ›๋Š”๊ฒƒ. ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋ฉ”์‹œ์ง€๋ฅผ ์ „๋‹ฌ๋ฐ›๋Š” ๊ฒƒ.

์นด์นด์˜คํ†ก์ด๋„ค?

๋‹จ์ˆœํžˆ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋‚ด๊ฐ€ ๋ณด๋‚ธ ๋ฉ”์‹œ์ง€๋ฅผ ์„œ๋ฒ„์—์„œ ์ €์žฅํ•˜๊ณ , ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋Œ๋ ค์ค€๋‹ค๋ฉด ๊ทธ๊ฒƒ์ด ์ฑ„ํŒ…์ด ์•„๋‹๊นŒ? ๋ผ๋Š” ์ƒ๊ฐ์„ ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๐Ÿถ ํ•œ๊ณ„

ํ•˜์ง€๋งŒ, ํฐ ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ์‚ฌ์šฉํ•˜๋Š” HTTP ๋ฐฉ์‹์€ ๋‚ด๊ฐ€ ์š”์ฒญ์„ ๋ณด๋ƒˆ์„ ๋•Œ, ๊ทธ๊ฒƒ์— ๋งž๋Š” ์‘๋‹ต๋งŒ ์„œ๋ฒ„์—์„œ ๋Œ๋ ค์ค€๋‹ค.

์ฆ‰, ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ์—†์ด ์Šค์Šค๋กœ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์‘๋‹ตํ•˜๋Š”๊ฒฝ์šฐ๋Š” ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

์‚ฌ์‹ค ์ฑ„ํŒ…์ด๋ž€๊ฒƒ์ด ๋‚ด๊ฐ€ ์•„๋ฌด๋Ÿฐ ์š”์ฒญ์„ ํ•˜์ง€ ์•Š์•„๋„, ์ƒ๋Œ€๋ฐฉ์ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๊ฒŒ๋œ๋‹ค๋ฉด, ์„œ๋ฒ„์—์„œ ๊ทธ ๋ฉ”์‹œ์ง€๋ฅผ ๋‚˜์—๊ฒŒ ๋Œ๋ ค์ค˜์•ผํ•œ๋‹ค.

๋งˆ์น˜ ์‹ค์‹œ๊ฐ„ ํ†ต์‹ ์„ ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ

๐ŸŽ webSocket

๋‘๊ฐœ์˜ ํ”„๋กœ๊ทธ๋žจ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š”๊ฒƒ.

ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š”๊ฒƒ.

httpํ†ต์‹ ์ด๋ž‘ ๊ฐ™์•„๋ณด์ด์ง€๋งŒ, ํด๋ผ์ด์–ธํŠธ ์š”์ฒญ์ด ์ „๋‹ฌ๋˜์–ด์•ผ๋งŒ ์„œ๋ฒ„๊ฐ€ ์‘๋‹ต์„ ํ•˜๋Š” ์ˆ˜๋™์ ์ธ ๊ฒƒ์ด ์•„๋‹Œ, ์„œ๋ฒ„์—์„œ๋„ ๋Šฅ๋™์ ์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Œ.

๋…ธ๋งˆ๋“œ์ฝ”๋” ์˜์ƒ์—์„œ๋Š”, ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๊ณ  ์ˆ˜์‹ ํ•˜์˜€์„ ๋•Œ ์—ฐ๊ฒฐ์ด ๋Š๊ธฐ๋Š”๊ฒƒ์ด ์•„๋‹Œ ์ฒซ connection์„ ํ†ตํ•ด ์—ฐ๊ฒฐ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ์„œ๋กœ ๊ตํ™˜ํ•œ๋‹ค๊ณ  ์–˜๊ธฐํ•˜์‹ฌ.

  1. ์–‘๋ฐฉํ–ฅ ํ†ต์‹ ์ด ๊ฐ€๋Šฅํ•จ. ์œ„์—์„œ ์„ค๋ช…๋œ ํŠน์ง•

  2. ์‹ค์‹œ๊ฐ„ ๋„คํŠธ์›Œํ‚น ์ฑ„ํŒ…, ์ฃผ์‹๊ณผ ๊ฐ™์ด ์ •ํ•ด์ง„ ์‹œ๊ฐ„์ด ์•„๋‹Œ ๋žœ๋คํ•œ ์‹œ๊ฐ„์— ๋ฐœ์ƒํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ทธ๋•Œ๋งˆ๋‹ค ํด๋ผ์ด์–ธํŠธ์— ๋ฐ˜์˜์ด ๋˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•จ

WebSocket์ด์ „, ์œ„์˜ ์–‘๋ฐฉํ–ฅ ํ†ต์‹ , ์‹ค์‹œ๊ฐ„ ๋„คํŠธ์›Œํ‚น์ด๋ผ๋Š” ํŠน์ง•์ด ํ•„์š”ํ•œ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๊ณ  ํ•จ.

HTTP Polling

์ผ์ • ์ฃผ๊ธฐ๋งˆ๋‹ค ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„์ƒ์œผ๋กœ ์š”์ฒญ์„ ์†ก์‹ ํ•จ. ํ•˜์ง€๋งŒ, ์ฑ„ํŒ…๊ณผ ๊ฐ™์€ ํ”„๋กœ๊ทธ๋žจ์—์„œ ์ •ํ•ด์ง„ ์‹œ๊ฐ„์— ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ํ˜•์„ฑ๋˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ์ด ์ƒ๊ธธ์ˆ˜ ์žˆ๊ณ , ์‹ค์‹œ๊ฐ„์ด๋ผ๊ณ  ํ•˜๊ธฐ์—” ์• ๋งคํ•จ.

HTTP Long Polling

์ •ํ•ด์ง„ ์‹œ๊ฐ„์— ์š”์ฒญ์„ ๋ณด๋‚ด์–ด ๋ถˆํ•„์š”ํ•œ ์š”์ฒญ์ด ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜, ๋ณ€๊ฒฝ๋œ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๊ฐ€ ์ƒ๊ธฐ์ž๋งˆ์ž ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ผ ์ˆ˜ ์—†๋‹ค๋Š” ๋ฌธ์ œ๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ฒ˜์Œ ์„œ๋ฒ„์— ์š”์ฒญ์ด ์ „๋‹ฌ๋˜์—ˆ์„ ๋•Œ, ๋ณ€ํ™”๊ฐ€ ์ƒ๊ธธ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•˜๋‹ค๊ฐ€ ์ƒ๊ธฐ๋ฉด ํด๋ผ์ด์–ธํŠธ๋กœ ์‘๋‹ต.

์–ด์ฐŒ๋˜์—ˆ๋“ , ๋งŽ์€ ์–‘์˜ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ๊ทธ ์ฃผ๊ธฐ๊ฐ€ ์งง์•„์ง€๋ฉด์„œ Polling๊ณผ ๋‹ค๋ฅผ๊ฒƒ์ด ์—†๊ฒŒ๋œ๋‹ค ํ•จ.

HTTP Streaming

์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์—ฐ๊ฒฐ์„ ๋Š์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์†ํ•ด์„œ ๋ฐ›์•„์˜ด.

ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์˜์ƒ์ •๋ณด๋ฅผ ๋ณด๋‚ด๋Š”๊ฒƒ์ด ๋Œ€ํ‘œ์ ์ด๋ผ๊ณ  ํ•จ.

์•„๋งˆ ์œ ํŠœ๋ธŒ, ํŠธ์œ„์น˜์™€ ๊ฐ™์€ ์ธํ„ฐ๋„ท ๋ฐฉ์†ก ํ”Œ๋žซํผ์—์„œ ์ด์™€๊ฐ™์€ ํŠน์ง•์ด ์ด์šฉ๋˜๋Š”๊ฒƒ์ด ์•„๋‹๊นŒ ์ƒ๊ฐํ•ด๋ด„

๋‹ค๋งŒ ์ฒ˜์Œ ํด๋ผ์ด์–ธํŠธ์—์„œ ์š”์ฒญ์ด ์ „๋‹ฌ๋œ ์ดํ›„์—๋Š” ๋ณ„๋‹ค๋ฅธ ์š”์ฒญ์—†์ด ์—ฐ๊ฒฐ๋œ ์ƒํƒœ๋กœ ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์ƒ์— ์กฐ๊ธˆ์”ฉ ๊ณ„์†ํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š”๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ๋ฐ์ดํ„ฐ์†ก์‹ ์ด ์–ด๋ ต๋‹ค๊ณ  ํ•จ.

๊ทธ๋ž˜์„œ ํด๋ผ์ด์–ธํŠธ์ƒ์œผ๋กœ ์˜์ƒ์„ ์ž˜๊ฐœ ๋‚˜๋ˆ„์–ด์„œ ์ „์†กํ•˜๋Š”๋ฐ์— ์ฃผ๋กœ ์“ฐ์ด๋Š”๊ฒƒ ๊ฐ™์Œ.

๋ชจ๋‘ ๊ณตํ†ต์ ์œผ๋กœ HTTPํ†ต์‹ ์„ ์‚ฌ์šฉํ•˜๋Š” ํ™˜๊ฒฝ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋น ๋ฅด๊ฒŒ, ์‹ค์‹œ๊ฐ„์„ ๋ชฉ์ ์œผ๋กœ ์ฃผ๊ณ ๋ฐ›์•„์•ผ ํ•˜๋‹ค๋ณด๋‹ˆ ๊ทœ๋ชจ๊ฐ€ ํฐ header๊ฐ€ ์ž์ฃผ ๊ตํ™˜๋˜๋Š” ์ƒํ™ฉ์ด๋ผ๊ณ  ํ•œ๋‹ค.

์—ฐ๊ฒฐ

WebSocket๋„ ์ผ๋ฐ˜ ์„œ๋ฒ„์™€์˜ ํ†ต์„ ์น˜๋Ÿผ ํ•ธ๋“œ์‰์ดํ‚น์˜ ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค๊ณ  ํ•จ

ํ•ธ๋“œ์‰์ดํ‚น. ์ฒ˜์Œ๋ณด์ง€๋งŒ ๋Œ€๋žต์ ์œผ๋กœ ์˜๋ฏธ๋ฅผ ์•Œ์•„๋ณด๋‹ˆ, ํด๋ผ์ด์–ธํŠธ์—์„œ ์„œ๋ฒ„๋กœ ์—ฐ๊ฒฐ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„์—์„œ๋Š” ์—ฐ๊ฒฐ ์‘๋‹ต์„ ํด๋ผ์ด์–ธํŠธ์— ๋ณด๋‚ด์–ด์„œ ์„œ๋กœ์˜ ์—ฐ๊ฒฐ ๊ณผ์ •์„ ํ•ธ๋“œ์‰์ดํ‚น์ด๋ผ๊ณ  ํ•˜๋Š”๊ฒƒ ๊ฐ™๋‹ค. ๋” ์•Œ์•„๋ณด์ž.

http(80), https(443) ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„œ๋ฒ„์— ์š”์ฒญ์„ ์ „๋‹ฌํ•˜๋Š”๋ฐ, ํ•ต์‹ฌ header ์†์„ฑ๋“ค์ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

// GET /chat
const header = {
  Host: javascript.info
  Origin: https://javascript.info
  Connection: Upgrade
  Upgrade: websocket
  Sec-WebSocket-Key: Iv8io/9s+lYFgZWcXczP8Q==
  Sec-WebSocket-Version: 13
}

Origin : webSocket์—ฐ๊ฒฐ์„ ํ•  ํด๋ผ์ด์–ธํŠธ ์ฃผ์†Œ Connection: ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํ”„๋กœํ† ์ฝœ์„ ๋ณ€๊ฒฝํ•˜๊ณ ์‹ถ๋‹ค๋Š” ์š”์ฒญ Upgrade : ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ณ€๊ฒฝํ•˜๊ณ ์‹ถ์€ ํ”„๋กœํ† ์ฝœ Sec-WebSocket-Key : ์—ฐ๊ฒฐ๋˜๋Š” ํ”„๋กœํ† ์ฝœ์˜ ๋ณด์•ˆ์„ ์œ„ํ•œ ํ‚ค

์ด๋ ‡๊ฒŒ ์ „์†ก์ด ๋˜๋ฉด ์„œ๋ฒ„์—์„œ๋Š” webSocket์ด ์—ฐ๊ฒฐ๋˜์—ˆ๋‹ค๋Š” ์‘๋‹ต์„ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†กํ•œ๋‹ค.

์ด ์ดํ›„์—๋Š” httpํ”„๋กœํ† ์ฝœ์ด ์•„๋‹Œ ws80 ํ˜น์€ wss(443) ํ”„๋กœํ† ์ฝœ์ด ์ ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

wss๋Š” https์ฒ˜๋Ÿผ SSL ๋ณด์•ˆ ์ธ์ฆ์ด ์ ์šฉ๋œ ํ”„๋กœํ† ์ฝœ์ด๋ผ๊ณ  ํ•จ

๋ฐ์ดํ„ฐ ์ „์†ก

webSocket ํ”„๋กœํ† ์ฝœ๋กœ ์—ฐ๊ฒฐ๋œ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›๋Š” ๊ตฌ์กฐ๋ฅผ webSocket frame๋ผ๊ณ  ํ•œ๋‹ค.

frame์€ header์™€ payload๋กœ ๊ตฌ์„ฑ๋˜์–ด์žˆ๋‹ค๊ณ  ํ•จ.

์ „๋‹ฌ๋˜๋Š” frame์˜ ํฌ๊ธฐ์— ๋”ฐ๋ผ frame header๊ฐ€ ๋‹ค๋ฅธ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๋Š”๋‹ค๋Š”๊ฒƒ ๊ฐ™๋‹ค.

header์˜ OPCODE๋ฅผ ํ†ตํ•ด ํ•ด๋‹น frame์ด ํ…์ŠคํŠธ ํ”„๋ ˆ์ž„์ธ์ง€, ์ด์ง„ ๋ฐ์ดํ„ฐ ํ”„๋ ˆ์ž„์ธ์ง€ ์•„๋‹ˆ๋ฉด webSocket์ปค๋„ฅ์…˜์„ ์ข…๋ฃŒํ•˜๋Š” ํ”„๋ ˆ์ž„์ธ์ง€ ๊ตฌ๋ถ„ํ•œ๋‹ค๊ณ  ํ•จ.

๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ๋“ค๋งŒ์„ ๊ณจ๋ผ๋ด„..

์ดํ›„์— ํ•จ๊ป˜ ์ „๋‹ฌ๋œ UTF-8 ํ˜•์‹์˜ payload๋ฅผ ์•Œ์•„๋ณผ์ˆ˜ ์žˆ๋Š” ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ๋””์ฝ”๋”ฉํ•˜๋Š”๊ฒƒ ๊ฐ™๋‹ค

webSocket ํ”„๋กœํ† ์ฝœ ํŠน์ง•

  1. ์ฒ˜์Œ ์ ‘์†์—์„œ๋งŒ http ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ธ๋“œ์‰์ดํ‚น์„ ํ•˜๊ธฐ ์œ„ํ•ด ํ•œ๋ฒˆ๋งŒ http header๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  2. ๋‹ค๋ฅธ ํฌํŠธ๊ฐ€ ์•„๋‹Œ ๊ธฐ์กด์˜ http, https ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•จ
  3. webSocket์—ฐ๊ฒฐ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตํ™˜ํ•˜๋Š” ๊ตฌ์กฐ๋Š” webSocket frame์„ ์‚ฌ์šฉํ•จ

ํ•œ๊ณ„

HTML5๋ถ€ํ„ฐ ์†Œ๊ฐœ๋œ ๊ธฐ์ˆ ๋กœ ์ด์ „์˜ ๋ฒ„์ „์—์„œ๋Š” ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•จ.

Socket.io, SockJS์™€ ๊ฐ™์€ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜์—ฌ webSocket์„ ํ˜ธํ™˜ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฒ„์ „์—์„œ ํŠน์ง•์ธ ์‹ค์‹œ๊ฐ„ ์›น์„ ๊ตฌํ˜„ํ•˜๋„๋ก ๋„์™€์คŒ

๋ธŒ๋ผ์šฐ์ €์™€ ์›น ์„œ๋ฒ„์˜ ์ข…๋ฅ˜, ๋ฒ„์ „์„ ํŒŒ์•…ํ•˜์—ฌ ์ ํ•ฉํ•œ ๊ธฐ์ˆ ์„ ์„ ํƒํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

๐Ÿ“ Socket.io

Web Socket์€ HTML5์˜ ๊ธฐ์ˆ ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์˜ค๋ž˜๋œ ๋ฒ„์ „์˜ ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” Web Socket์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ ํ•œ๋‹ค.

๋Œ€ํ‘œ์ ์ธ IE.. ์š”์ฆ˜ IE์— ๋Œ€ํ•œ ์ง€์›์ด ๋Œ€๋ถ€๋ถ„ ๋Š๊ธฐ๊ณ  ์žˆ๋‹ค๋ผ๋Š” ์นด๋”๋ผ ํ†ต์‹ (feat Youtube)

์ด์ฒ˜๋Ÿผ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์œ„ํ•ด ์ƒ๊ธด๊ฒƒ์ด Socket.io๋ผ๊ณ  ํ•œ๋‹ค.

Socket.io๋Š” Node.js๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ธฐ์ˆ ๋กœ, ๊ฑฐ์˜ ๋ชจ๋“  ์›น๋ธŒ๋ผ์šฐ์ €์™€ ๋ชจ๋ฐ”์ผ ์žฅ์น˜๋ฅผ ์ง€์›ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ผ๊ณ  ํ•œ๋‹ค.

๋งŒ์•ฝ, Web Socket์„ ์ง€์›ํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ผ๋ฉด ํ•ด๋‹น ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•˜๊ณ , ๊ทธ๋ ‡์ง€ ์•Š์€ ๋ธŒ๋ผ์šฐ์ €๋ผ๋ฉด ๊ธฐ์กด์˜ HTTP๋ฅผ ์ด์šฉํ•ด์„œ ํ‰๋‚ด๋ฅผ ๋‚ธ๋‹ค๊ณ  ํ•œ๋‹ค.

์–ด๋–ป๊ฒŒ ํ‰๋‚ด๋ฅผ ๋‚ด๋Š”๊ฑฐ์ง€..?

๐Ÿญ ๊ฐ„๋‹จํ•œ ์ฑ„ํŒ… ๊ตฌํ˜„

Socket.io๋Š” ๊ณต์‹์‚ฌ์ดํŠธ์—์„œ ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด ์ฒดํ—˜ํ•ด ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ฝ”๋“œ์™€, ๊ฐ์ข… API๋ฅผ ์ •๋ฆฌํ•ด๋†“์€ ๋ฌธ์„œ๊ฐ€ ์žˆ์œผ๋‹ˆ ํ•œ๋ฒˆ ๊ฐ€๋ณด๋Š”๊ฒŒ ์ข‹์„๋“ฏ ํ•˜๋‹ค! - ์•„๋ž˜ ์ฐธ๊ณ  ํ™•์ธ

๊ณต์‹ ์‚ฌ์ดํŠธ์— ๋‚˜์™€์žˆ๋Š” ๊ฐ„๋‹จํ•œ ์ฑ„ํŒ… ์‚ฌ์ดํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณธ ๊ฒฝํ—˜์ด๋‹ค.

ํ™•์ธํ•ด๋ณด๊ณ ์‹ถ์€ ํŠน์ • ์ƒํ™ฉ๋“ค์ด ์žˆ์–ด, ์‚ด์ง ์ˆ˜์ •ํ•˜์˜€๋‹ค.

๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ

1

๐Ÿฅž server

const path = require('path')
const express = require('express')
const app = express()
const http = require('http')
const server = http.createServer(app)
const port = 3000
const { Server } = require('socket.io')
const io = new Server(server)
const basePath = path.join(__dirname, '..', '/')

app.get('/', (req, res) => {
  res.sendFile(basePath + 'public/index.html')
})

app.get('/room', (req, res) => {
  res.sendFile(basePath + 'public/room.html')
})

io.on('connection', socket => {
  // ์†Œํ‚ท ์—ฐ๊ฒฐ
  console.log('Socket Connected')

  // ์ž…์žฅ ๊ฐ์ง€ยท๋ฐ˜ํ™˜
  socket.on('join', name => {
    // ๋‚˜๋ฅผ ์ œ์™ธํ•œ ์—ฐ๊ฒฐ๋œ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ - broadcast.emit
    // socket.broadcast.emit("join", name);
    // ๋‚˜๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ์ „๋‹ฌ - emit
    io.emit('join', name)
  })

  // ํ‡ด์žฅ ๊ฐ์ง€ยท๋ฐ˜ํ™˜
  //    ํ˜„์žฌ ์ ‘์†ํ•œ ๊ณณ์ด ์ฑ„ํŒ…๋ฐฉ์ด์—ฌ์„œ, ํ‡ด์žฅํ•˜๋ฉด ์†Œํ‚ท ์ข…๋ฃŒ์‹œํ‚ด
  socket.on('leave', name => {
    io.emit('leave', name)
    // socket.broadcast.emit("leave", name);
    socket.disconnect(true)
  })

  // ์ฑ„ํŒ… ๊ฐ์ง€ยท๋ฐ˜ํ™˜
  socket.on('chat', msg => {
    io.emit('chat', msg)
  })

  // ์†Œํ‚ท ์ข…๋ฃŒ
  socket.on('disconnect', () => {
    console.log('Socket Disconnected ')
  })
})

server.listen(port, () => {
  console.log(`Server is connected on ${port}`)
})
  • ์ „๋ฐ˜์ ์œผ๋กœ ๋ณด์•˜์„ ๋•Œ, .on ์ด๋ผ๋Š” API๊ฐ€ ํด๋ผ์ด์–ธํŠธ Socket ์—์„œ์˜ ์š”์ฒญ์„ ์„œ๋ฒ„์˜ Socket์—์„œ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ ๊ฐ™๋‹ค.
  • .emit์€ .on๊ณผ ๋ฐ˜๋Œ€๋กœ, ์„œ๋ฒ„์˜ Socket์—์„œ ํด๋ผ์ด์–ธํŠธ์˜ Socket์œผ๋กœ ๋ณด๋‚ด์ฃผ๋Š” ์—ญํ™œ์„ ํ•œ๋‹ค.
  • connection, disconnect์™€ ๊ฐ™์ด Socket์—์„œ ์ •ํ•œ ๋„ค์ด๋ฐ๋„ ์žˆ์ง€๋งŒ, join, leave์™€ ๊ฐ™์€๊ฒƒ์€ ์ปค์Šคํ…€ํ•œ ๋„ค์ด๋ฐ์ด๋‹ค.

    ์ปค์Šคํ…€ ์ด๋ฒคํŠธ์ฒ˜๋Ÿผ ์ด ๋„ค์ด๋ฐ์ด ์ดํ›„์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์ด๋ฒคํŠธ ํ‚ค๋ผ๊ณ  ๋ณด๋Š”๊ฒŒ ์ข‹์„๋“ฏ ํ•˜๋‹ค.

  • ํ˜„์žฌ๋Š”, Socket์— ์ ‘์†ํ•˜๋ฉด ๋ฐ”๋กœ ์ฑ„ํŒ…์— ์ฐธ์—ฌํ•˜๋Š”๊ตฌ์กฐ์ด์ง€๋งŒ, Room์ด๋ผ๋Š” ๊ฐœ๋…๊ณผ .to API๋ฅผ ํ†ตํ•ด ์ƒํ˜ธ์ž‘์šฉ์—๋Œ€ํ•œ ๊ฒƒ์„ ๊ตฌ๋ถ„์ง€์„์ˆ˜? ์žˆ๋Š”๊ฒƒ ๊ฐ™์•˜๋‹ค.

    ์ผ์ข…์˜ ์นด์นด์˜คํ†ก ๋Œ€ํ™”๋ฐฉ ๊ฐ™์€?

๐Ÿ– index.html

<a href="room">๋ฐฉ์œผ๋กœ ์ด๋™</a>
  • connection์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๊ณ ์‹ถ์–ด, Socket์ด ์‹คํ–‰๋˜๋Š” ๊ฒฝ๋กœ๋ฅผ ๊ตฌ๋ถ„์ง€์–ด๋†“๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ํ•˜์˜€๋‹ค.

    ๋ณ„ ์˜๋ฏธ๋Š” ์—†์Œ..

๐Ÿ” room.html

// Socket CDN
<script src="/socket.io/socket.io.js"></script>

// html
<div class="bar">
  <button id="out">Out</button>
</div>
<div id="messages"></div>
<form id="form" class="bar" action="">
  <input id="input" autocomplete="off" /><button>Send</button>
</form>

// script
const form = document.querySelector("#form");
const input = document.querySelector("#input");
const messages = document.querySelector("#messages");
const out = document.querySelector("#out");
const name = "์ƒ๋ฏผ";

// ์†Œํ‚ท ์—ฐ๊ฒฐ
const socket = io();

// ๋‚˜์˜ ์ž…์žฅ์„ ๋ชจ๋‘์—๊ฒŒ ์•Œ๋ฆผ
socket.emit("join", name);

// ๋ˆ„๊ตฐ๊ฐ€ ์ž…์žฅํ–ˆ์„ ๋•Œ ์•Œ๋ฆผ ๋ฐ›์Œ
socket.on("join", name => {
  recordChat(`${name} ๋‹˜์ด ์ž…์žฅํ•˜์…จ์Šต๋‹ˆ๋‹ค.`);
});

// ์ฑ„ํŒ… ์ž…๋ ฅ
form.addEventListener("submit", e => {
  e.preventDefault();
  if (input.value) {
    socket.emit("chat", { name, msg: input.value });
    input.value = "";
  }
});

// ๋ˆ„๊ตฐ๊ฐ€์˜ ์ฑ„ํŒ… ๋ฐ›์•„์˜ด
socket.on("chat", ({ name, msg }) => {
  recordChat(`${name} : ${msg}`);
});

// ๋‚ด๊ฐ€ ๋– ๋‚˜๊ธฐ ์œ„ํ•œ ๋ฒ„ํŠผ
out.addEventListener("click", e => {
  e.preventDefault();
  socket.emit("leave", name);
});

// ๋ˆ„๊ตฐ๊ฐ€ ๋– ๋‚ฌ์„ ๋•Œ ์•Œ๋ฆผ ๋ฐ›์•„์˜ด
socket.on("leave", name => {
  recordChat(`${name} ๋‹˜์ด ํ‡ด์žฅํ•˜์…จ์Šต๋‹ˆ๋‹ค.`);
});

function recordChat(msg) {
  const item = document.createElement("p");
  item.textContent = msg;
  messages.appendChild(item);
  window.scrollTo(0, document.body.scrollHeight);
}
  • ์„œ๋ฒ„์˜ Socket๊ณผ ๋™์ผํ•˜๊ฒŒ, on์œผ๋กœ ํŠน์ • ์ด๋ฒคํŠธ ํ‚ค์— ๋Œ€ํ•œ ๊ฐ์ง€๋ฅผ ํ•˜๊ณ , .emit์œผ๋กœ ํŠน์ • ์ด๋ฒคํŠธ ํ‚ค์— ๋Œ€ํ•œ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.
  • const socket = io(); ์ด ๋ถ€๋ถ„์—์„œ, url์„ ์ธ์ž๋กœ ๋ณด๋‚ด ๋™์ผ ํฌํŠธ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ํฌํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ๋„ ์žˆ๋Š”๊ฒƒ ๊ฐ™์•˜๋‹ค.

    ๋ฌผ๋ก , ์„œ๋ฒ„์—์„œ cors์™€ ๊ด€๋ จ๋˜์–ด ํ—ˆ์šฉ ์ฃผ์†Œ๋กœ ์ง€์ •ํ•ด์ค˜์•ผ ํ•จ.

  • ํ˜„์žฌ๋Š” ๋ฐ”๋กœ Socket์— ์ ‘์†ํ•˜๋„๋ก ๋˜์–ด์žˆ์ง€๋งŒ, ํ•„์š”์— ๋”ฐ๋ผ ์‚ฌ์šฉ์ž๊ฐ€ ์›ํ•  ๋•Œ connect๋ฅผ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค.

๐ŸŒฎ ๊ฒฐ๊ณผ

๐Ÿฅง ์ฑ„ํŒ… ์ฐธ์—ฌ - ํ‡ด์žฅ / ํด๋ผ์ด์–ธํŠธ

2
  • ์›๋ž˜๋Œ€๋กœ๋ผ๋ฉด, ํ‡ด์žฅํ•˜์˜€์„ ๋•Œ ๋‹ค์‹œ index.html๋กœ ๋Œ์•„๊ฐ€์ง€๋งŒ, ํ‡ด์žฅํ–ˆ๋‹ค๋Š” ๋ฌธ๊ตฌ๊ฐ€ ์ž˜ ๋œจ๋Š”์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ด๋™ํ•˜์ง„ ์•Š์•˜๋‹ค.

๐Ÿท ์ฑ„ํŒ… ์ฐธ์—ฌ - ํ‡ด์žฅ / ์„œ๋ฒ„

3
  • ์ด๊ฒŒ ๋ญ”๊ฐ€ ์‹ถ๊ฒ ์ง€๋งŒ, room.html๋กœ ์ด๋™ํ•˜์˜€์„ ๋•Œ, Socket Connected๊ฐ€ ์„œ๋ฒ„์—์„œ ํ˜ธ์ถœ๋˜๊ณ , ํด๋ผ์ด์–ธํŠธ์—์„œ ๋‚˜๊ฐ€๊ธฐ๋ฅผ ๋ˆŒ๋ €์„ ๋•Œ, ์„œ๋ฒ„์—์„œ Socket Disconnected๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • ๋‹น์—ฐํžˆ, Socket Disconnected๊ฐ€ ํ˜ธ์ถœ๋œ ๋’ค๋กœ๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฌด์Šจ ์ฑ„ํŒ…์„ ์ฒ˜๋„ ์•„๋ฌด๋Ÿฐ ๋ณ€ํ™”๊ฐ€ ์—†๋‹ค.

๐Ÿฅฎ ํ›„๊ธฐ

์ •๋ง ์žฌ๋ฏธ์žˆ๋Š”๊ฒƒ ๊ฐ™๋‹ค. ์นด์นด์˜คํ†ก์ด๋ž‘ ๋น„์œ ๋ฅผ ํ•ด๋ณธ๋‹ค๋ฉด

  1. ์นด์นด์˜คํ†ก ๋กœ๊ทธ์ธ - Socket Connect

  2. ๋Œ€ํ™”๋ฐฉ - Socket Room

    • ๋Œ€ํ™”๋ฐฉ์˜ ์ด์ „ ๋Œ€ํ™”๋‚ด์šฉ์€ DB๋กœ ์ €์žฅํ•˜๊ณ , ํ•ด๋‹น ๋ฐฉ์— ์ž…์žฅํ–ˆ์„ ๋•Œ ๊ธฐ๋ก์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฐฉ์‹
    • ๊ฐ๊ฐ์˜ ๋Œ€ํ™”๋ฐฉ์— ๋Œ€ํ•œ ๋ณ€ํ™”(๊ฐ™์€ id์˜ ๋Œ€ํ™”๋ฐฉ์„ ์‚ฌ์šฉํ•˜๊ณ ์žˆ๋Š” ์‚ฌ๋žŒ์˜ ์ฑ„ํŒ…)๋ฅผ ์„œ๋ฒ„์—์„œ๋Š” .emit์œผ๋กœ ๋ณด๋‚ด๊ณ , ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” .on์œผ๋กœ ๊ฐ์ง€ํ•จ

      ๋งŒ์•ฝ React๋ผ๋ฉด, .on์œผ๋กœ ๋ฐ›์•„์˜จ ํšŸ์ˆ˜๋ฅผ ์นด์šดํŒ…ํ•˜์—ฌ ๋ˆ„์ ๋œ ์ƒˆ๋กœ์šด ๋ฉ”์‹œ์ง€ ๊ฐฏ์ˆ˜ ์ถœ๋ ฅ? ๊ฐ€์žฅ ์ตœ์‹ ์˜ ๋Œ€ํ™”๋งŒ thumbnail๋กœ ๋…ธ์ถœ

  3. ์นด์นด์˜คํ†ก ๋กœ๊ทธ์•„์›ƒ - Socket disConnect

์ด๋Ÿฐ ๋Š๋‚Œ์ด์ง€ ์•Š์„๊นŒ..?

๊ฑด๋ฐฉ์ง€๊ฒŒ ๊ฐํžˆ ์˜ˆ์ƒ์„ ํ•ด๋ณด์•˜๋‹ค.

๐Ÿฉ ์ฐธ๊ณ 


@SangMin
๐Ÿ‘† H'e'story

๐Ÿš€GitHub